/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.uml_generator;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.transaction.TransactionStatus;
import org.springframework.util.ObjectUtils;

import com.genia.toolbox.basics.bean.Predicate;
import com.genia.toolbox.basics.bean.impl.ConjunctionPredicate;
import com.genia.toolbox.basics.bean.impl.NotPredicate;
import com.genia.toolbox.basics.bean.impl.ReferenceUnOrderedPairImpl;
import com.genia.toolbox.basics.exception.BundledException;
import com.genia.toolbox.basics.exception.technical.TechnicalException;
import com.genia.toolbox.basics.i18n.EnumDescriptable;
import com.genia.toolbox.basics.i18n.I18nMessage;
import com.genia.toolbox.basics.i18n.impl.I18nMessageImpl;
import com.genia.toolbox.basics.manager.StringManager;
import com.genia.toolbox.basics.process.ProxyHelper;
import com.genia.toolbox.persistence.bean.Persistable;
import com.genia.toolbox.persistence.criteria.Criteria;
import com.genia.toolbox.persistence.criteria.PropertyField;
import com.genia.toolbox.persistence.criteria.SimplePropertyField;
import com.genia.toolbox.persistence.spring.configurator.PersistableConfigurator;
import com.genia.toolbox.persistence.spring.dependency.impl.AbstractPersistableDependency;
import com.genia.toolbox.spring.provider.message.bean.impl.SimpleMessageProvider;
import com.genia.toolbox.spring.provider.plugin.impl.AbstractSimpleSpringProviderPlugin;
import com.genia.toolbox.spring.transaction.bean.TransactionCallbackWithoutResult;
import com.genia.toolbox.uml_generator.model.AbstractClassModel;
import com.genia.toolbox.uml_generator.model.AbstractObject;
import com.genia.toolbox.uml_generator.model.AttributeModel;
import com.genia.toolbox.uml_generator.model.DataTypeModel;
import com.genia.toolbox.uml_generator.model.impl.ExistentDataTypeModel;

/**
 * Class containing constants for the generation.
 */
public class Constants
{
  /**
   * predicate that remove class tagged with the ignore value.
   */
  private static final class RemoveTaggedClass
      implements Predicate<AbstractObject>
  {
    /**
     * the tag to remove.
     */
    private String tagToRemove;



    /**
     * constructor.
     * 
     * @param tagToRemove
     *          the tag to remove
     */
    private RemoveTaggedClass(String tagToRemove)
    {
      this.tagToRemove = tagToRemove;
    }



    /**
     * evaluate the predicate on the object.
     * 
     * @param object
     *          the object to evaluate
     * @return <code>true</code> if an only if the object satisfies the
     *         predicate
     */
    public boolean evaluate(AbstractObject object)
    {
      return !object.hasStereotype(tagToRemove);
    }
  }

  /**
   * predicate that remove interface.
   */
  private static final class RemoveInterface
      implements Predicate<AbstractClassModel>
  {
    /**
     * evaluate the predicate on the object.
     * 
     * @param object
     *          the object to evaluate
     * @return <code>true</code> if an only if the object satisfies the
     *         predicate
     */
    public boolean evaluate(AbstractClassModel object)
    {
      return !object.isInterface();
    }
  }

  /**
   * predicate that remove the identifier.
   */
  private static final class RemoveIdentifier
      implements Predicate<AttributeModel>
  {
    /**
     * evaluate the predicate on the object.
     * 
     * @param object
     *          the object to evaluate
     * @return <code>true</code> if an only if the object satisfies the
     *         predicate
     */
    public boolean evaluate(AttributeModel object)
    {
      return !object.getName().equals(ATTRIBUTE_NAME_IDENTIFIER);
    }
  }

  /**
   * predicate that remove the un-mappable Attributes.
   */
  private static final class RemoveUnMappable
      implements Predicate<AttributeModel>
  {
    /**
     * evaluate the predicate on the object.
     * 
     * @param object
     *          the object to evaluate
     * @return <code>true</code> if an only if the object satisfies the
     *         predicate
     */
    public boolean evaluate(AttributeModel object)
    {
      return object.isMappable();
    }
  }

  /**
   * predicate that keep only attribute that must be escaped.
   */
  private static final class KeepToEscape
      implements Predicate<AttributeModel>
  {
    /**
     * evaluate the predicate on the object.
     * 
     * @param object
     *          the object to evaluate
     * @return <code>true</code> if an only if the object satisfies the
     *         predicate
     */
    public boolean evaluate(AttributeModel object)
    {
      return object.hasStereotype(ESCAPE_STEREOTYPE);
    }
  }

  /**
   * predicate that match {@link Persistable} model.
   */
  private static final class IsPersistableInterface
      implements Predicate<AbstractClassModel>
  {
    /**
     * evaluate the predicate on the object.
     * 
     * @param object
     *          the object to evaluate
     * @return <code>true</code> if an only if the object satisfies the
     *         predicate
     */
    public boolean evaluate(AbstractClassModel object)
    {
      return object.getQualifiedName().equals(PERSISTABLE_MODEL.getQualifiedName());
    }
  }

  /**
   * the model for a PersistableDependency.
   */
  public static final DataTypeModel PERSISTABLE_DEPENDENCY_MODEL = new ExistentDataTypeModel(AbstractPersistableDependency.class, "");

  /**
   * the model for a {@link PropertyField}.
   */
  public static final DataTypeModel PROPERTY_FIELD_MODEL = new ExistentDataTypeModel(PropertyField.class, "");

  /**
   * the model for a {@link SimplePropertyField}.
   */
  public static final DataTypeModel SIMPLE_PROPERTY_FIELD_MODEL = new ExistentDataTypeModel(SimplePropertyField.class, "");

  /**
   * the model for a Persistable.
   */
  public static final DataTypeModel PERSISTABLE_MODEL = new ExistentDataTypeModel(Persistable.class, "");

  /**
   * the model for a {@link StringManager}.
   */
  public static final DataTypeModel STRING_MANAGER_MODEL = new ExistentDataTypeModel(StringManager.class, "");

  /**
   * the model for a {@link Criteria}.
   */
  public static final DataTypeModel CRITERIA_MODEL = new ExistentDataTypeModel(Criteria.class, "");

  /**
   * the Model for {@link TransactionCallbackWithoutResult}.
   */
  public static final DataTypeModel TRANSACTION_CALLBACK_WITHOUT_RESULT_MODEL = new ExistentDataTypeModel(TransactionCallbackWithoutResult.class, "");

  /**
   * the model for {@link EnumDescriptable}.
   */
  public static final DataTypeModel ENUM_DESCRIPTABLE_MODEL = new ExistentDataTypeModel(EnumDescriptable.class, "");

  /**
   * the model for {@link TransactionStatus}.
   */
  public static final DataTypeModel TRANSACTION_STATUS_MODEL = new ExistentDataTypeModel(TransactionStatus.class, "");

  /**
   * the model for a Object.
   */
  public static final DataTypeModel OBJECT_MODEL = new ExistentDataTypeModel(Object.class, "");

  /**
   * the model for a {@link ProxyHelper}.
   */
  public static final DataTypeModel PROXY_HELPER_MODEL = new ExistentDataTypeModel(ProxyHelper.class, "");

  /**
   * the model for a {@link Set}.
   */
  public static final DataTypeModel SET_MODEL = new ExistentDataTypeModel(Set.class, "Hash");

  /**
   * the model for a {@link List}.
   */
  public static final DataTypeModel LIST_MODEL = new ExistentDataTypeModel(List.class, "Array");

  /**
   * the model for a {@link TechnicalException}.
   */
  public static final DataTypeModel TECHNICAL_EXCEPTION_MODEL = new ExistentDataTypeModel(TechnicalException.class, "");

  /**
   * the model for a {@link BundledException}.
   */
  public static final DataTypeModel BUNDLED_EXCEPTION_MODEL = new ExistentDataTypeModel(BundledException.class, "");

  /**
   * the model for a {@link ReferenceUnOrderedPairImpl}.
   */
  public static final DataTypeModel REFERENCE_UN_ORDERED_PAIR_MODEL = new ExistentDataTypeModel(ReferenceUnOrderedPairImpl.class, "");

  /**
   * the model for a {@link ThreadLocal}.
   */
  public static final DataTypeModel THREAD_LOCAL_MODEL = new ExistentDataTypeModel(ThreadLocal.class, "");

  /**
   * the model for a {@link Map}.
   */
  public static final DataTypeModel MAP_MODEL = new ExistentDataTypeModel(Map.class, "Hash");

  /**
   * the model for a {@link Map}.
   */
  public static final DataTypeModel VOID_MODEL = new ExistentDataTypeModel(void.class, "");

  /**
   * the model for a {@link SimpleMessageProvider}.
   */
  public static final DataTypeModel SIMPLE_MESSAGE_PROVIDER_MODEL = new ExistentDataTypeModel(SimpleMessageProvider.class, "");

  /**
   * the model for a {@link PersistableConfigurator}.
   */
  public static final DataTypeModel PERSISTABLE_CONFIGURATOR_MODEL = new ExistentDataTypeModel(PersistableConfigurator.class, "");

  /**
   * the model for {@link AbstractSimpleSpringProviderPlugin}.
   */
  public static final DataTypeModel PLUGIN_CLASS_MODEL = new ExistentDataTypeModel(AbstractSimpleSpringProviderPlugin.class, "");

  /**
   * tag that marks a class to be ignore by the generation.
   */
  public static final String IGNORE_STEREOTYPE = "ignore";

  /**
   * tag that marks a class as being a template.
   */
  public static final String TEMPLATE_STEREOTYPE = "template";

  /**
   * tag that marks a property as needing to be escaped.
   */
  public static final String ESCAPE_STEREOTYPE = "escape";

  /**
   * tag that marks a property as needing to be not null.
   */
  public static final String NOT_NULL_STEREOTYPE = "not-null";

  /**
   * tag that marks a property as needing to be unique.
   */
  public static final String UNIQUE_STEREOTYPE = "unique";

  /**
   * tag that declares the name of the unique constraint.
   */
  public static final String UNIQUE_KEY_TAG = "key";

  /**
   * tag that marks a property as needing to be indexed.
   */
  public static final String INDEXED_STEREOTYPE = "indexed";

  /**
   * tag that marks a property as needing to use the 2nd level cache.
   */
  public static final String CACHED_STEREOTYPE = "cached";

  /**
   * tag that give the name of the index for a property that must be indexed.
   * This is not mandatory.
   */
  public static final String INDEX_NAME_TAG = "index-name";

  /**
   * the tag that allow to specify the type of generator for a primary key.
   * TODO use this to allow specifying the type of generator, and in particular to allow assigned generator.
   */
  public static final String GENERATOR_TAG = "generator";

  /**
   * the name of the Spring plugin class.
   */
  public static final String PLUGIN_CLASS_NAME = "GeneratedSpringPlugin";

  /**
   * the name of the generated Spring config file.
   */
  public static final String SPRING_CONFIG_FILE = "generated-spring-config.xml";

  /**
   * url for interface i18nMessage.
   */
  public static final String URL_I18N_MESSAGE = I18nMessage.class.getCanonicalName();

  /**
   * url for i18nMessageImpl.
   */
  public static final String URL_I18N_MESSAGE_IMPL = I18nMessageImpl.class.getCanonicalName();

  /**
   * url for enum Type.
   */
  public static final String URL_ENUM_USER_TYPE_BY_ID = "com.genia.toolbox.persistence.hibernate.mapping.type.AbstractEnumUserTypeById";

  /**
   * url for collections.
   */
  public static final String URL_COLLECTIONS = Collections.class.getCanonicalName();

  /**
   * url for ObjectUtils.
   */
  public static final String URL_OBJECT_UTILS = ObjectUtils.class.getCanonicalName();

  /**
   * url for Arrays.
   */
  public static final String URL_ARRAYS = Arrays.class.getCanonicalName();

  /**
   * the implements reserved word.
   */
  public static final String IMPLEMENTS_RESERVED_WORD = "implements";

  /**
   * the extends reserved word.
   */
  public static final String EXTENDS_RESERVED_WORD = "extends";

  /**
   * the suffix to add to the names of class for the delegate.
   */
  public static final String DELEGATE_SUFFIX = "Delegate";

  /**
   * the suffix to add to the package names of implementation class.
   */
  public static final String IMPLEMENTATION_PACKAGE_SUFFIX = "impl";

  /**
   * the comment to add when a file is auto-generated.
   */
  public static final String COMMENT_WARNING_GENERATED = "<p>WARNING: This file is auto-generated. All modifications will be lost. All modifications must be done on the UML model.";

  /**
   * the suffix to add to the name of class used as hibernate type.
   */
  public static final String MAPPING_SUFFIX = "HibernateType";

  /**
   * the suffix to add to the package names of mapping class.
   */
  public static final String MAPPING_PACKAGE_SUFFIX = "mapping";

  /**
   * the suffix to add to internal objects.
   */
  public static final String INTERNAL_SUFFIX = "Internal";

  /**
   * the suffix to add to the implementation classes.
   */
  public static final String IMPLEMENTATION_SUFFIX = "Impl";

  /**
   * the suffix to add to the dependency class.
   */
  public static final String DEPENDENCY_SUFFIX = "Dependency";

  /**
   * the suffix to add to the package names of dependency class.
   */
  public static final String DEPENDENCY_PACKAGE_SUFFIX = "dependency";

  /**
   * the name of the attribute used as an identifier.
   */
  public static final String ATTRIBUTE_NAME_IDENTIFIER = "identifier";

  /**
   * predicate that remove class tagged with the template value.
   */
  public static final Predicate<AbstractObject> REMOVE_TEMPLATE_PREDICATE = new RemoveTaggedClass(TEMPLATE_STEREOTYPE);

  /**
   * predicate that remove class tagged with the ignore value.
   */
  public static final Predicate<AbstractObject> REMOVE_IGNORED_CLASS_PREDICATE = new RemoveTaggedClass(IGNORE_STEREOTYPE);

  /**
   * predicate that remove interface.
   */
  public static final Predicate<AbstractClassModel> REMOVE_INTERFACE_PREDICATE = new RemoveInterface();

  /**
   * predicate that remove interface.
   */
  public static final Predicate<AbstractClassModel> KEEP_ONLY_INTERFACE_PREDICATE = new NotPredicate<AbstractClassModel>(REMOVE_INTERFACE_PREDICATE);

  /**
   * predicate that find {@link Persistable} model.
   */
  public static final Predicate<AbstractClassModel> IS_PERSISTABLE_INTERFACE_PREDICATE = new IsPersistableInterface();

  /**
   * predicate that find not {@link Persistable} model.
   */
  public static final Predicate<AbstractClassModel> IS_NOT_PERSISTABLE_INTERFACE_PREDICATE = new NotPredicate<AbstractClassModel>(IS_PERSISTABLE_INTERFACE_PREDICATE);

  /**
   * predicate that remove Identifier attribute.
   */
  public static final Predicate<AttributeModel> REMOVE_IDENTIFIER_PREDICATE = new RemoveIdentifier();

  /**
   * predicate that key only the generateble classes.
   */
  @SuppressWarnings("unchecked")
  public static final Predicate<AbstractClassModel> ONLY_GENERATABLE_CLASSES = new ConjunctionPredicate<AbstractClassModel>(Constants.REMOVE_INTERFACE_PREDICATE,
      Constants.REMOVE_IGNORED_CLASS_PREDICATE, Constants.REMOVE_TEMPLATE_PREDICATE);

  /**
   * prefix for plural objects.
   */
  public static final String PLURAL_SUFFIX = "s";

  /**
   * preficate that remove the association from the attributes.
   */
  public static final Predicate<AttributeModel> REMOVE_UN_MAPPABLE_PREDICATE = new RemoveUnMappable();

  /**
   * preficate that keep only the attributes that must be escaped.
   */
  public static final Predicate<AttributeModel> KEEP_TO_ESCAPE_PREDICATE = new KeepToEscape();

  /**
   * preficate that keep only the association from the attributes.
   */
  public static final Predicate<AttributeModel> REMOVE_MAPPABLE_PREDICATE = new NotPredicate<AttributeModel>(REMOVE_UN_MAPPABLE_PREDICATE);

  /**
   * prefix for messages objects.
   */
  public static final String MESSAGES_SUFFIX = "Messages";
  
  /**
   * stereotype name used to skip hibernate mapping generation.
   */
  public static final String SKIP_MAPPING_STEREOTYPE = "skipMapping";



  /**
   * private constructor.
   */
  private Constants()
  {
    // do nothing.
  }

}
